package migrate

import (
	"fmt"

	"gorm.io/gorm"
)

// ModuleMigrator 模块迁移接口
type ModuleMigrator interface {
	// GetName 返回模块名称
	GetName() string
	// GetModels 返回需要迁移的模型
	GetModels() []interface{}
	// Migrate 执行模块特定的迁移逻辑（如创建关联表、索引等）
	Migrate(db *gorm.DB) error
	// Seed 执行模块数据初始化
	Seed(db *gorm.DB) error
	// GetDependencies 返回依赖的模块名称（用于确定迁移顺序）
	GetDependencies() []string
}

// MigrationManager 迁移管理器
type MigrationManager struct {
	db        *gorm.DB
	migrators map[string]ModuleMigrator
}

// NewMigrationManager 创建迁移管理器
func NewMigrationManager(db *gorm.DB) *MigrationManager {
	return &MigrationManager{
		db:        db,
		migrators: make(map[string]ModuleMigrator),
	}
}

// RegisterMigrator 注册模块迁移器
func (m *MigrationManager) RegisterMigrator(migrator ModuleMigrator) {
	m.migrators[migrator.GetName()] = migrator
}

// AutoMigrate 执行所有模块的自动迁移
func (m *MigrationManager) AutoMigrate() error {
	// 1. 按依赖关系排序模块
	orderedMigrators, err := m.sortByDependencies()
	if err != nil {
		return err
	}

	// 2. 执行表结构迁移
	for _, migrator := range orderedMigrators {
		models := migrator.GetModels()
		if len(models) > 0 {
			if err := m.db.AutoMigrate(models...); err != nil {
				return err
			}
		}
	}

	// 3. 执行模块特定的迁移逻辑
	for _, migrator := range orderedMigrators {
		if err := migrator.Migrate(m.db); err != nil {
			return err
		}
	}

	return nil
}

// SeedData 执行所有模块的数据初始化
func (m *MigrationManager) SeedData() error {
	// 按依赖关系排序模块
	orderedMigrators, err := m.sortByDependencies()
	if err != nil {
		return err
	}

	// 暂时禁用外键约束
	m.db.Exec("SET FOREIGN_KEY_CHECKS = 0")
	defer m.db.Exec("SET FOREIGN_KEY_CHECKS = 1")

	// 执行数据初始化
	for _, migrator := range orderedMigrators {
		if err := migrator.Seed(m.db); err != nil {
			return err
		}
	}

	return nil
}

// sortByDependencies 按依赖关系对模块进行拓扑排序
func (m *MigrationManager) sortByDependencies() ([]ModuleMigrator, error) {
	var result []ModuleMigrator
	visited := make(map[string]bool)
	visiting := make(map[string]bool)

	var visit func(name string) error
	visit = func(name string) error {
		if visiting[name] {
			return fmt.Errorf("检测到循环依赖: %s", name)
		}
		if visited[name] {
			return nil
		}

		migrator, exists := m.migrators[name]
		if !exists {
			return fmt.Errorf("模块 %s 不存在", name)
		}

		visiting[name] = true
		for _, dep := range migrator.GetDependencies() {
			if err := visit(dep); err != nil {
				return err
			}
		}
		visiting[name] = false
		visited[name] = true

		result = append(result, migrator)
		return nil
	}

	for name := range m.migrators {
		if err := visit(name); err != nil {
			return nil, err
		}
	}

	return result, nil
}
